package bigdata.monitor.binlog.utils;

import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.PathNotFoundException;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
 * 使用 JsonPath 从 Binlog JSON 提取变更字段
 */
@Slf4j
public class JsonPathFieldExtractor {

    /**
     * 提取指定字段的 before/after 值
     * @param binlogJson 完整 Binlog JSON
     * @param outputFields 逗号分隔的字段列表
     * @return JSON 字符串: {"field": {"before": "...", "after": "..."}}
     */
    public static String extractChangedFields(String binlogJson, String outputFields) {
        if (!StringUtils.hasText(outputFields)) {
            return "{}";
        }

        try {
            DocumentContext context = JsonPath.parse(binlogJson);
            JSONObject result = new JSONObject();

            for (String field : outputFields.split(",")) {
                field = field.trim();
                if (field.isEmpty()) {
                    continue;
                }

                String beforePath = "$.before." + field;
                String afterPath = "$.after." + field;

                Object beforeVal = safeRead(context, beforePath);
                Object afterVal = safeRead(context, afterPath);

                JSONObject pair = new JSONObject();
                // 直接 put null，后续序列化时启用 WriteMapNullValue
                pair.put("before", beforeVal != null ? beforeVal.toString() : null);
                pair.put("after", afterVal != null ? afterVal.toString() : null);

                result.put(field, pair);
            }

            // 启用 WriteMapNullValue 以输出 null 字段
            return result.toJSONString(JSONWriter.Feature.WriteMapNullValue);

        } catch (Exception e) {
            log.warn("Failed to extract changed fields from binlog json", e);
            return "{}";
        }
    }

    private static Object safeRead(DocumentContext context, String path) {
        try {
            return context.read(path);
        } catch (PathNotFoundException e) {
            return null;
        }
    }
}
